#include "stdafx.h"
#include <glut.h>
#include "NxPhysics.h"
#include "Renderer.h"

CRenderer::CRenderer( ) :
	m_PhysicsSDK( NULL ),
	m_Scene( NULL )
{
	InitializePhysX( );
}

CRenderer::~CRenderer( )
{
	if( m_PhysicsSDK != NULL )
	{
		if(m_Scene != NULL) m_PhysicsSDK->releaseScene(*m_Scene);
		m_Scene = NULL;
		NxReleasePhysicsSDK(m_PhysicsSDK);
		m_PhysicsSDK = NULL;
	}
}

bool CRenderer::InitializePhysX( )
{
	// Initialize PhysicsSDK
	NxPhysicsSDKDesc thePhysicsSDKDescription;
	NxSDKCreateError theErrorCode = NXCE_NO_ERROR;
	
	m_PhysicsSDK = NxCreatePhysicsSDK( NX_PHYSICS_SDK_VERSION, NULL, NULL, thePhysicsSDKDescription, &theErrorCode );
	if( m_PhysicsSDK == NULL ) 
		return false;

	m_PhysicsSDK->setParameter( NX_SKIN_WIDTH, 0.05f );

	// Create a scene
	NxSceneDesc theSceneDescription;
	theSceneDescription.gravity = NxVec3( 0.0f, -9.81f, 0.0f );
	m_Scene = m_PhysicsSDK->createScene( theSceneDescription );
	if( m_Scene == NULL ) 
		return false;

	// Set default material
	NxMaterial* theDefaultMaterial = m_Scene->getMaterialFromIndex( 0 );
	theDefaultMaterial->setRestitution( 0.0f );
	theDefaultMaterial->setStaticFriction( 0.5f );
	theDefaultMaterial->setDynamicFriction( 0.5f );

	// Create ground plane
	NxPlaneShapeDesc thePlaneDescription;
	NxActorDesc theActorDescription;
	theActorDescription.shapes.pushBack( &thePlaneDescription );
	m_Scene->createActor( theActorDescription );

	return true;
}

void CRenderer::CreateCube( const NxVec3& inPosition, const int inSize, const NxVec3* inInitialVelocity )
{
	if( m_Scene == NULL ) return;

	// Create body
	NxBodyDesc theBodyDescription;
	theBodyDescription.angularDamping = 0.5f;
	if( inInitialVelocity )
		theBodyDescription.linearVelocity = *inInitialVelocity;

	NxBoxShapeDesc theBoxDescription;
	theBoxDescription.dimensions = NxVec3( ( float ) inSize, ( float ) inSize, ( float ) inSize );

	NxActorDesc theActorDescription;
	theActorDescription.shapes.pushBack( &theBoxDescription );
	theActorDescription.body = &theBodyDescription;
	theActorDescription.density	= 10.0f;
	theActorDescription.globalPose.t = inPosition;
	m_Scene->createActor(theActorDescription)->userData = ( void* ) size_t( inSize );
	
	printf( "Total: %d actors\n", m_Scene->getNbActors( ) );
}

void CRenderer::PreRender( )
{
}

void CRenderer::Render( )
{
	static bool s_CreateCube = false;
	if ( !s_CreateCube )
	{
		CreateCube( NxVec3( 0.0f, 20.0f, 0.0f ), 1 );
		s_CreateCube = true;
	}

	if( m_Scene == NULL )
		return;
	
	// Start simulation (non blocking)
	m_Scene->simulate( 1.0f / 60.0f );

	// Clear buffers
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	// Setup projection matrix
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	gluPerspective( 60.0f, ( float ) glutGet( GLUT_WINDOW_WIDTH ) / ( float ) glutGet( GLUT_WINDOW_HEIGHT ), 1.0f, 10000.0f );
	gluLookAt( 0.0f, 20.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

	// Setup modelview matrix
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity( );

	// Render all actors
	int theActorNumber = m_Scene->getNbActors( );
	NxActor** theActors = m_Scene->getActors( );
	while( theActorNumber-- )
	{
		NxActor* theActor = *theActors++;
		if( !theActor->userData ) 
			continue;

		// Render theActor
		glPushMatrix( );
		float theActorMatrix[16];
		theActor->getGlobalPose( ).getColumnMajor44( theActorMatrix );
		glMultMatrixf( theActorMatrix );
		glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
		glutSolidCube( float( size_t( theActor->userData ) ) * 2.0f );
		glPopMatrix( );

		// Render shadow
		glPushMatrix( );
		const static float theShadowMatrix[]={ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1 };
		glMultMatrixf( theShadowMatrix );
		glMultMatrixf( theActorMatrix );
		glDisable( GL_LIGHTING );
		glColor4f( 0.1f, 0.2f, 0.3f, 1.0f );
		glutSolidCube( float( size_t( theActor->userData ) ) * 2.0f );
		glEnable( GL_LIGHTING );
		glPopMatrix( );
	}

	// Fetch simulation results
	m_Scene->flushStream( );
	m_Scene->fetchResults( NX_RIGID_BODY_FINISHED, true );
}

void CRenderer::PostRender( )
{
}